﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Remoting.Messaging;
using System.ServiceModel;
using System.Runtime.Remoting.Proxies;
using System.ServiceModel.Channels;

namespace Cherry.Agile.ServiceModel {
    public class ClientRealProxy<T> : RealProxy where T :class {


        EndpointAddress _remoteAddress;
        Binding _binding;
        bool _isBidirectional;
        private ClientRealProxy(Binding binding, EndpointAddress remoteAddress, bool isBidirectional= false)
            : base(typeof(T)) {
                _remoteAddress = remoteAddress;
                _binding = binding;
                _isBidirectional = isBidirectional;
        }

        public override IMessage Invoke(IMessage msg) {

            T channel = ClientFactory.Current.CreateClient<T>(this._binding, _remoteAddress, _isBidirectional);
            IMethodCallMessage methodCall = (IMethodCallMessage)msg;
            IMethodReturnMessage methodReturn = null;
            object[] copiedArgs = Array.CreateInstance(typeof(object), methodCall.Args.Length) as object[];
            methodCall.Args.CopyTo(copiedArgs, 0);
            try {
                object returnValue = methodCall.MethodBase.Invoke(channel, copiedArgs);
                methodReturn = new ReturnMessage(returnValue, copiedArgs, copiedArgs.Length, methodCall.LogicalCallContext, methodCall);
                (channel as ICommunicationObject).Close();
            } catch (Exception ex) {
                if (ex.InnerException is CommunicationException || ex.InnerException is TimeoutException) {
                    (channel as ICommunicationObject).Abort();
                }

                if (ex.InnerException != null) {
                    methodReturn = new ReturnMessage(ex.InnerException, methodCall);
                } else {
                    methodReturn = new ReturnMessage(ex, methodCall);
                }
            }

            return methodReturn;
        }
        
        /// <summary>
        /// 创建WCF Client代理
        /// </summary>
        /// <typeparam name="TC">接口类型</typeparam>
        /// <param name="binding"><see cref="Binding>"/></param>
        /// <param name="remoteAddress"><see cref="EndpointAddress"/></param>
        /// <param name="isBidirectional">是否传递上线文消息头</param>
        /// <returns></returns>
        public static TC CreateProxy<TC>(Binding binding, EndpointAddress remoteAddress, bool isBidirectional = false) where TC:class {
            return new ClientRealProxy<TC>(binding, remoteAddress, isBidirectional) as TC;
        }
    }
}

